package spreadsheet;

import java.util.HashSet;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * Spreadsheet that contains all cells and evaluates them in proper order.
 * 
 * @author James Marquardt
 *
 */
public class Spreadsheet {
	
	/**
	 * An array to store all cells in spreadsheed.
	 */
	private Cell[][] cell_arr;
	/**
	 * Rows in this spreadsheet.
	 */
	private int my_rows;
	/**
	 * Columns in this spreadsheet.
	 */
	private int my_columns;
	/**
	 * A set of all the cells that depend on a cell (directly or indirectly).
	 */
	private Set<Cell> my_depends_on_me_set;
	
	/**
	 * Creates a new Spreadsheed object.
	 * 
	 * @param the_rows The number of rows in the spreadsheet.
	 * @param the_columns The number of columns in the spreadsheet.
	 */
	public Spreadsheet(int the_rows, int the_columns) {
		cell_arr = new Cell[the_rows][the_columns];
		my_rows = the_rows;
		my_columns = the_columns;
		
		for(int i = 0; i < the_rows; i++){
			for(int j = 0; j < the_columns; j++){
				
				cell_arr[i][j] = new Cell(i, j, this);
			
			}
		}
		
		my_depends_on_me_set = new HashSet<Cell>();
	}
	
	/**
	 * Returns the specified cell.
	 * @param row The row the cell is in.
	 * @param column The column the cell is in.
	 * @return The specified cell.
	 */
	public Cell getCell(int row, int column) {
		
		return cell_arr[row-1][column-1];
		
	}
	
	/**
	 * Calls the evaluate method of each cell in the appropriate order
	 */
	public void evaulateSpreadSheet(){
		
		for(int i = 0; i < my_rows; i++){
			for(int j = 0; j < my_columns; j++){
				
				cell_arr[i][j].evaluateCell();
			
			}
		}
		
	}
	
	/**
	 * Checks for cycles within the spreadsheet.
	 * 
	 * @param the_cell The current cell that is being checked for a cycle.
	 * @throws Exception When a cycle is detected.
	 */
	public void checkCycles(final Cell the_cell) throws Exception {
		
		//Adds all dependencies on this cell to the set.
		my_depends_on_me_set.addAll(the_cell.getDependsOnMeSet());
		
		//A set of all the cells that this cell depends on.
		Set<Cell> the_comp_set = new HashSet<Cell>();
		
		//This set gets updated every time checkCycles is called.
		the_comp_set.addAll(the_cell.getDependsOnMap().values()); 
		
		//The intersection of dependencies (forward and backward)
		the_comp_set.retainAll(my_depends_on_me_set);

		for(Cell i : the_comp_set) {
		
			//If there is an intersection, there is a cycle.
			if(!the_comp_set.isEmpty()) {
				
				//Reset the cell cycle was noted at to break it.
				i.resetCell();
				
				JOptionPane.showMessageDialog(new JFrame(), "Cycle Detected", "Error",
						JOptionPane.ERROR_MESSAGE);
				
				throw new Exception("Cycle detected");
						
			}
		
		}
		
	}
	
}
